package com.letoo.sso.core.service.impl;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.letoo.sso.common.domain.ContextConstants;
import com.letoo.sso.common.domain.Result;
import com.letoo.sso.common.domain.ResultCode;
import com.letoo.sso.common.utils.AESUtils;
import com.letoo.sso.common.utils.AssertUtil;
import com.letoo.sso.common.utils.MD5Utils;
import com.letoo.sso.core.service.AppBaseConfigService;
import com.letoo.sso.core.service.UserTokenService;
import com.letoo.sso.dataaccess.dao.cahce.UserTokenCacheDAO;
import com.letoo.sso.dataaccess.dao.db.BaseDBDAO;
import com.letoo.sso.dataaccess.dao.db.UserTokenDBDAO;
import com.letoo.sso.dataaccess.domain.dbo.UserTokenDO;

/**
 * user和token关系的服务接口实现
 * 
 * @author: dengjie
 */
@Service("userTokenService")
public class UserTokenServiceImpl extends BaseServiceImpl<UserTokenDO> implements UserTokenService {
    /**
     * 日志
     */
    protected final Logger log = LoggerFactory.getLogger(getClass());

    @Resource
    private UserTokenDBDAO userTokenDBDAO;
    @Resource
    private UserTokenCacheDAO userTokenCacheDAO;
    @Resource
    private AppBaseConfigService appBaseConfigService;

    @Override
    protected BaseDBDAO<UserTokenDO> getDAO() {
        return userTokenDBDAO;
    }

    @Override
    public boolean saveOrUpdate(UserTokenDO userTokenDO) {
        int rows = userTokenDBDAO.userIdIsExisted(userTokenDO);
        int updateRows = 0;
        int insertRows = 0;
        if (rows >= 1) {
            // 已经存在userId，那么就更新token即可
            updateRows = userTokenDBDAO.updateToken(userTokenDO);
        } else {
            insertRows = userTokenDBDAO.save(userTokenDO);
        }
        if (updateRows == 1 || insertRows == 1) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Result validateToken(final long userId, final String token, final String uri, final String sign, final String x) {
        Result result = new Result(ResultCode.COMMON_SUCCESS, true);
        // 输入校验
        AssertUtil.isNotBlank(token, "token is blank");
        AssertUtil.isNotBlank(uri, "uri is blank");
        AssertUtil.isNotBlank(sign, "sign is blank");
        AssertUtil.gt(userId, 0l, "userId must gt zero,the userId is:" + userId);
        // 校验该用户ID是否被系统禁用.禁用的时候，建议删除t_user_token.这样用户就会重新登陆。重新登陆的时候会校验用户是否禁用。
        // NO TODO 后续做管理端的时候，提供接口进行禁用用户。

        //
        //
        String tokenSecretKey = appBaseConfigService.getAppBaseConfig(ContextConstants.APP_ID, ContextConstants.TOKEN_SECRET_KEY);
        String realToken = AESUtils.decrypt(token, tokenSecretKey);
        // 根据客户端传递过来的uri、token和固定字符串生成的sign
        String signSecretKey = appBaseConfigService.getAppBaseConfig(ContextConstants.APP_ID, ContextConstants.SIGN_SECRET_KEY);
        String signInServer = MD5Utils.md5AndBase64(uri + realToken + signSecretKey);
        // 校验sign值是否一致
        if (!StringUtils.equals(signInServer, sign)) {
            result.setResultCode(ResultCode.SSO_VALIDATE_IS_FAILED);
            result.setSuccess(false);
            log.error("the sign is not equals,the client sign is:" + sign + "the server sign is:" + signInServer);
            return result;
        }
        // 对userId和token进行校验
        // 先从缓存中获取userId&token进行校验
        String tokenInServer = userTokenCacheDAO.getByUserId(userId);
        if (StringUtils.isBlank(tokenInServer)) {
            // cache中是空，则从DB中获取token信息
            String tokenInDb = userTokenDBDAO.queryTokenByUserId(userId);
            tokenInServer = tokenInDb;
        }
        if (!StringUtils.equals(realToken, tokenInServer)) {
            log.error("the client send token string is:" + token + " the tokenkey is: " + tokenSecretKey);
            log.error("the token is not equals,the client token is:" + realToken + "the server token is:" + tokenInServer);
            // 客户端传入token与服务器存储token不相等，则返回给客户端校验token失败需要客户端重新登陆。
            result.setResultCode(ResultCode.SSO_VALIDATE_IS_FAILED);
            result.setSuccess(false);
        }
        return result;
    }

}
